Fun with enums (Fun with flags)
Sep 23, 2018
Fun with Enums - API Endpoint
Swift enums are pretty awesome. For a person like me, whose first programming language was C (a long, long, long time ago), it's like a breath of fresh air.
Enums are first-class types and can adopt features traditionally supported only by classes:
- Conform to protocols
- Computed properties
- Instance methods
- Initializers
Basic Enums
Let's start with a classic example
enum Guitar {
case classical
case electric
case acoustic
}
Associated values
Associated values are a perfect way to add additional information to enums. Imagine for instance that you would like to add some information to our enum example. A guitar has a serial number. An electric guitar could have one, two or more pickups, an acoustic guitar could be electrified or not and so on. Let's translate this into code.
enum Guitar {
case classical(serialNumber: String)
case electric(serialNumber: String, pickups: Int)
case acoustic(serialNumber: String, electrified: Bool)
}
let classicalGuitar = Guitar.classical(serialNumber: "SW87234")
let electricGuitar = Guitar.electric(serialNumber: "HG0983", pickups: 2)
let acousticGuitar = Guitar.acoustic(serialNumber: "JJ8888", electrified: false)
if case let Guitar.acoustic(serialNumber, electrified) = acousticGuitar {
print("Acoustic guitar. Serial number\(serialNumber). Electrified: \(electrified)")
}
Output:
Acoustic guitar. Serial numberJJ8888. Electrified: false
Enums and protocols
For example, we could model API Endpoints with enums. What we would like to do is build different endpoints based on our needs. Take the TFL Unified API for instance. To retrieve lines status for a few lines (victoria, piccadilly and central), we'd have to build something like this https://api.tfl.gov.uk//Line/victoria,piccadilly,central/Status
Wouldn't it be great if, with a simple line of code, we could get this url? That's pretty cool but you will say...Ooh great!....show me the code!!! Ok, let's do it.
We define a protocol with a url variable
protocol EndPointProtocol {
var url: URL { get }
}
enum LineEndPoint {
case validmodes
case lineStatus([String])
}
extension LineEndPoint: EndPointProtocol {
var url: URL {
guard var url = URLComponents(string: "https://api.tfl.gov.uk") else { fatalError("Error") }
switch self {
case .validmodes:
url.path = "/Line/Meta/Modes"
case .lineStatus(let idLines):
let linesIdcommaseparated = getCommaSeparated(array: idLines)
url.path = "/Line/\(linesIdcommaseparated)/Status"
}
let urlFinal = url.url
return urlFinal!
}
private func getCommaSeparated(array: [String]) -> String {
return array.map { String($0)}.joined(separator: ",")
}
}
The only thing we have to do is:
let lineStatus = LineEndPoint.lineStatus(["victoria","piccadilly","central"])
print("Line status endpoint: \(lineStatus.url)")
Output:
Line status endpoint: https://api.tfl.gov.uk/Line/victoria,piccadilly,central/Status
And that's it. A fancy and elegant way of getting endpoints.